package com.youxin.busfoundation.net;

import java.net.URI;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.youxin.foundation.utils.JsonUtils;

/**
 * 网络请求
 * 
 * @author yingde.cao
 *
 */
public class WebVisitor {
	private static WebVisitor webVisitor = new WebVisitor();
	private final static int DEFAULT_TIMEOUT = 1000;
	private int timeout = DEFAULT_TIMEOUT;
	private String encodingName = "UTF-8";

	/*
	 * restTemplate.getMessageConverters() .add(0, new
	 * StringHttpMessageConverter(Charset.forName("UTF-8")));
	 */
	public WebVisitor() {
	}

	public static WebVisitor instance() {
		return webVisitor;
	}

	public String getEncodingName() {
		return encodingName;
	}

	public void setEncodingName(String encodingName) {
		this.encodingName = encodingName;
	}

	public int getTimeout() {
		return Math.max(timeout, DEFAULT_TIMEOUT);
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	private ClientHttpRequestFactory getClientHttpRequestFactory() {
		timeout = 10000;
		HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
		httpRequestFactory.setConnectionRequestTimeout(timeout);
		httpRequestFactory.setConnectTimeout(timeout);
		httpRequestFactory.setReadTimeout(timeout);
		return httpRequestFactory;
	}

	private Charset getCharset() {
		try {
			return Charset.forName(encodingName);
		} catch (Exception e) {
			return Charset.defaultCharset();
		}
	}

	public String httpGet(String url, Object... uriVariables) {
		RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
		restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(getCharset()));
		return restTemplate.getForObject(url, String.class, uriVariables);
	}

	@SuppressWarnings("unchecked")
	public <T> T httpGetToEntity(String url, Class<T> cls) {
		String response = httpGet(url);
		try {
			return (T) JsonUtils.stringToObject(response, cls);
		} catch (Exception e) {
			return null;
		}

	}

	public ResponseEntity<String> httpGetEntity(String url, Object... uriVariables) {
		RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
		restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(getCharset()));
		ResponseEntity<String> response = restTemplate.getForEntity(url, String.class, uriVariables);
		return response;
	}

	/**
	 * 获取HttpGet请求
	 * 
	 * @param url
	 *            网络地址
	 * @param cls
	 *            类
	 * @param uriVariables
	 * @return
	 */
	public <T> ResponseEntity<T> httpGetEntity(String url, Class<T> cls, Object... uriVariables) {
		RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
		restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(getCharset()));
		ResponseEntity<T> response = restTemplate.getForEntity(url, cls, uriVariables);
		return response;
	}

	/**
	 * http获取结果和status
	 * 
	 * @param url
	 * @return
	 */
	public ResponseEntity<String> httpGetEntity(String url) {
		RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
		restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(getCharset()));
		ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
		return response;
	}

	/**
	 * post请求
	 * 
	 * @param url
	 *            url链接
	 * @param postParams
	 *            参数body参数,转换为JSON String
	 * @return String
	 */
	public String httpPostJsonBody(String url, Object bodyObject)
	{
		return httpPostJsonBody(url, bodyObject, null);
	}
	
	public String httpPostJsonBody(String url, Object bodyObject,Map<String, String> headersMap) {
		ObjectMapper mapper = new ObjectMapper();
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
	//	restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(getCharset()));
		restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter(mapper));

		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		if (headersMap != null) {
			for (Entry<String, String> entry : headersMap.entrySet()) {
				headers.add(entry.getKey(), entry.getValue());
			}
		}
		HttpEntity<Object> entity = new HttpEntity<Object>(bodyObject,headers);
		String result = restTemplate.postForObject( url, entity, String.class);	   
		return result;
	}

	/**
	 * Post请求Object
	 * 
	 * @param url
	 * @param cls
	 * @param body
	 * @return
	 */
	public <T> T httpPostWithObject(String url, Class<T> cls, Object body) {
		return httpPostWithObject(url,cls,body,null);
	}
	
	/**
	 * Post请求
	 * @description 
	 * @param url 地址
	 * @param cls 对象class
	 * @param bodyObject body中的Object对象
	 * @param headersMap 自定义头
	 * @return
	 */
	public <T> T httpPostWithObject(String url, Class<T> cls, Object bodyObject, Map<String, String> headersMap) {
		String content=httpPostJsonBody(url, bodyObject, headersMap);
		T t=JsonUtils.stringToFasterxmlObject(content, cls);		
		return t;
	}

	/**
	 * Post请求返回ResponseEntity
	 * 
	 * @param url
	 *            URL
	 * @param cls
	 *            返回的类
	 * @param body
	 *            传送的参数
	 * @return
	 */
	public <T> ResponseEntity<T> httpPostEntityWithObject(String url, Class<T> cls, Object body) {
		RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
		restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(getCharset()));
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		String jsonString = JsonUtils.objectToFasterxmlJsonString(body);
		HttpEntity<String> formEntity = new HttpEntity<String>(jsonString, headers);
		ResponseEntity<T> result = restTemplate.postForEntity(url, formEntity, cls);
		return result;
	}

	/**
	 * Post Async
	 * 
	 * @param url
	 * @param cls
	 * @param body
	 * @return
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	public <T> ResponseEntity<String> httpPostEntityAsyncWithObject(String url, Class<T> cls, Object body)
			throws InterruptedException, ExecutionException {

		return httpPostEntityAsyncWithObject(url, cls, body, new ListenableFutureCallback<ResponseEntity<String>>() {
			@Override
			public void onSuccess(ResponseEntity<String> result) {
				System.out.println(result.getBody());
				// Need assertions
			}

			@Override
			public void onFailure(Throwable t) {
				t.printStackTrace();
			}
		});

		// AsyncRestTemplate restTemplate = new AsyncRestTemplate();
		// HttpHeaders headers = new HttpHeaders();
		// MediaType type = MediaType.parseMediaType("application/json;
		// charset=UTF-8");
		// headers.setContentType(type);
		// headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
		// String jsonString = JsonUtils.objectToFasterxmlJsonString(body);
		// HttpEntity<String> requestEntity = new HttpEntity<String>(jsonString,
		// headers);
		// Class<String> responseType = String.class;
		//
		// ListenableFuture<ResponseEntity<String>> futureEntity =
		// restTemplate.exchange(URI.create(url),
		// org.springframework.http.HttpMethod.POST, requestEntity,
		// responseType);
		//
		// futureEntity.addCallback(new
		// ListenableFutureCallback<ResponseEntity<String>>() {
		// @Override
		// public void onSuccess(ResponseEntity<String> result) {
		// System.out.println(result.getBody());
		// // Need assertions
		// }
		//
		// @Override
		// public void onFailure(Throwable t) {
		// t.printStackTrace();
		// }
		// });
		//
		// ResponseEntity<String> result = null;
		// result = futureEntity.get();
		// return result;
	}

	public <T> ResponseEntity<String> httpPostEntityAsyncWithObject(String url, Class<T> cls, Object body,
			ListenableFutureCallback<ResponseEntity<String>> callback) throws InterruptedException, ExecutionException {
		AsyncRestTemplate restTemplate = new AsyncRestTemplate();
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
		String jsonString = JsonUtils.objectToFasterxmlJsonString(body);
		HttpEntity<String> requestEntity = new HttpEntity<String>(jsonString, headers);
		Class<String> responseType = String.class;

		ListenableFuture<ResponseEntity<String>> futureEntity = restTemplate.exchange(URI.create(url),
				org.springframework.http.HttpMethod.POST, requestEntity, responseType);
		futureEntity.addCallback(callback);
		// futureEntity.addCallback(new
		// ListenableFutureCallback<ResponseEntity<String>>() {
		// @Override
		// public void onSuccess(ResponseEntity<String> result) {
		// System.out.println(result.getBody());
		// // Need assertions
		// }
		//
		// @Override
		// public void onFailure(Throwable t) {
		// t.printStackTrace();
		// }
		// });

		ResponseEntity<String> result = null;
		result = futureEntity.get();
		return result;
	}

	public <T> ResponseEntity<String> httpGetEntityAsyncWithObject(String url)
			throws InterruptedException, ExecutionException {
		AsyncRestTemplate template = new AsyncRestTemplate();
		// String url = "http://localhost:8770/log";//休眠5秒的服务
		// 调用完后立即返回（没有阻塞）
		ListenableFuture<ResponseEntity<String>> futureEntity = template.getForEntity(url, String.class);
		// 异步调用后的回调函数
		futureEntity.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
			@Override
			public void onSuccess(ResponseEntity<String> result) {
				System.out.println(result.getBody());
				// Need assertions
			}

			@Override
			public void onFailure(Throwable t) {
				t.printStackTrace();
			}
		});
		ResponseEntity<String> result = futureEntity.get();
		return result;
	}

}
